---@class List
---@type List
List = Class(function(self, ...)
    self._data = {}   -- 列表存储数据源
    self._length = 0  -- 列表长度
    self._string = "" -- 列表数据内容
    self._show = true -- 展示列表数据内容

    for _, value in ipairs({ ... }) do
        if value ~= nil then
            self._data[self._length + 1] = value
        end
    end
    self:update()
end)

-- 注册列表数据类型
DATA_TYPE_REGISTERS["list"] = function(cur_type, obj)
    return cur_type == "table" and obj.is_a and obj:is_a(List)
end

-- 列表字符串化
function List:__tostring()
    if self._show then
        return string.format("<List %d>(%s)", self._length, self._string)
    else
        return string.format("<List %d>", self._length)
    end
end

-- 获取列表某一位置元素
---@param index integer 列表索引(非零整数), 当该数为负数时, 从末尾开始向前查询
function List:__index(index)
    -- 获取列表类方法
    if type(index) == "string" and string.match(index, "^%a[%a%d_]*$") then
        local method = rawget(getmetatable(self), index)
        if type(method) == "function" then
            return method
        else
            return
        end
    end

    -- 获取列表指定位置元素
    if type(index) == "integer" and index ~= 0 then
        if math.abs(index) > self:size() then
            return
        end
        if index < 0 then
            index = self:size() + index + 1
        end

        return rawget(self._data, index)
    end
end

-- 修改某一位置元素
---@param index integer 位置索引(非零自然数), 超过列表索引范围则添加至列表末尾
---@param obj any 修改后的元素
function List:__newindex(index, obj)
    if type(index) == "integer" and index > 0 then
        if obj == nil then
            table.remove(self._data, index)
        else
            if index > self:size() + 1 then
                index = self:size() + 1
            end
            rawset(self._data, index, obj)
        end
        self:update()
    end
end

-- 列表执行函数
function List:__call()
end

-- +运算符, 合并两个列表
---@param obj List 将该列表元素合并至当前列表中
function List:__add(obj)
    if type(obj) == "list" then
        for _, value in ipairs(obj) do
            table.insert(self._data, value)
        end
        self:update()
    end
end

-- #运算符, 获取列表长度(推荐使用size函数), lua版本5.2及以上支持, 游戏版本5.1
function List:__len()
    return self._length
end

-- 遍历迭代器(兼容已处理), lua版本5.2及以上支持, 游戏版本5.1
function List:__pairs()
    return ipairs(self._data)
end

-- 遍历迭代器(兼容已处理), lua版本5.2及以上支持, 游戏版本5.1
function List:__ipairs()
    return ipairs(self._data)
end

-- 展示/不展示列表数据内容
function List:show()
    self._show = not self._show
end

-- 更新列表
function List:update()
    self._length = #self._data
    self._string = table.concat(self._data, ", ")
end

-- 获取列表元素个数
---@return integer
function List:size()
    return self._length
end

-- 列表末尾添加新的元素
function List:append(...)
    for _, obj in ipairs({ ... }) do
        if obj ~= nil then
            table.insert(self._data, obj)
        end
    end
    self:update()
end

-- 列表某位置插入一个元素
---@param index integer 插入位置, 非零整数, 超过列表长度则添加至末尾/头部, 当该值为负数时从末尾向前插入(即倒数第二)
---@param obj any 要插入的元素
function List:insert(index, obj)
    if obj ~= nil and type(index) == "integer" and index ~= 0 then
        if index > 0 then
            index = index > self:size() + 1 and self:size() + 1 or index
        else
            index = math.abs(index) >= self:size() and 1 or self:size() + index + 1
        end

        table.insert(self._data, index, obj)
        self:update()
    end
end

-- 取出列表某位置的元素
---@param index integer 元素索引位置(非零整数), 默认取出最后一个元素, 当该值为负数时从末尾向前取出元素
---@return any
function List:pop(index)
    if index == nil then
        index = self:size()
    end
    if type(index) == "integer" and index ~= 0 then
        if math.abs(index) > self:size() then
            return
        end
        if index < 0 then
            index = self:size() + index + 1
        end

        local value = table.remove(self._data, index)
        self:update()

        return value
    end
end

--移除列表内最先找到的元素
---@overload fun(obj:any):nil
---@param obj any 要移除的元素
---@param reverse boolean 从末尾向前查询
---@return nil
function List:remove(obj, reverse)
    if reverse then
        for index = self:size(), 1, -1 do
            if self._data[index] == obj then
                table.remove(self._data, index)
                break
            end
        end
    else
        for index, value in ipairs(self._data) do
            if value == obj then
                table.remove(self._data, index)
                break
            end
        end
    end
    self:update()
end

-- 查找列表内元素
---@overload fun(value:any):List
---@overload fun(value:any, reverse:boolean):List
---@param obj any 要查询的元素
---@param fn fun(List.value:any, V:any):boolean 查找条件函数, 默认元素本身
---@param reverse boolean 从末尾向前查询
---@return List 所有该元素索引
function List:find(obj, fn, reverse)
    if obj == nil then
        return
    end
    if type(fn) ~= "function" then
        if reverse == nil then
            reverse = fn == true
        end
        fn = op.eq
    end

    local res = List()

    if reverse then
        for index = self:size(), 1, -1 do
            if fn(self._data[index], obj) then
                res:append(index)
            end
        end
    else
        for index = 1, self:size() do
            if fn(self._data[index], obj) then
                res:append(index)
            end
        end
    end

    if res:size() > 0 then
        return res
    end
end

-- 获取列表内满足条件的元素
---@param fn fun(V:any):boolean 过滤处理函数
---@return List
function List:filter(fn)
    local res = List()

    for _, obj in ipairs(self._data) do
        if fn(obj) == true then
            res:append(obj)
        end
    end

    return res
end

-- 获取列表随机一个元素
---@return any
function List:random()
    if self:size() > 0 then
        return self._data[math.random(self:size())]
    end
end

-- 反转列表元素位置
function List:reverse()
    local i, j = 1, self:size()

    while i < j do
        self._data[i], self._data[j] = self._data[j], self._data[i]
        i = i + 1
        j = j - 1
    end
end

-- 批量处理列表内元素
---@overload fun(fn:function):List
---@param fn fun(V:any, params:table|nil):any 批量处理函数
---@param params table 批量处理函数处理元素时需要额外传入的处理参数
---@return List
function List:map(fn, params)
    local res = List()

    for _, value in ipairs(self._data) do
        res:append(fn(value, params))
    end

    return res
end

-- 列表排序
---@overload fun():nil
---@param fn fun(V1:any, V2:any):boolean 排序方法, 默认升序
function List:sort(fn)
    if type(fn) ~= "function" then
        fn = nil
    end

    table.sort(self._data, fn)
end
